#pragma once

#if defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#include <HTTPClient.h>
#elif defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#endif

#include <Preferences.h>
#include <string.h> // for memcpy and strlen
#include <Ticker.h>

#define RESTARTCOUNT 4
class smartConfig_
{
private:
    smartConfig_() {} // 私有化构造函数

    struct ConfigType
    {
        char stassid[32]; // STA 模式下的 WiFi 名称，最大长度为 32 个字符
        char stapsw[64];  // STA 模式下的 WiFi 密码，最大长度为 64 个字符
        char cuid[40];    // 未知用途，最大长度为 40 个字符
        char ctopic[32];  // 未知用途，最大长度为 32 个字符
        uint8_t reboot;   // 重启次数，用于记录设备重启的次数，范围为 0 到 255
        uint8_t magic;    // 魔数，用于识别和维护存储在 EEPROM 中的数据有效性，通常为 0xAA
    } config;

    Ticker delayTimer;   // 延时重启
    Ticker restartTimer; // 延时 2s，用于检测连续重启次数

    char configFlag = 0;              // 配网标志位， 0：不需要配网，1：需要配网
    const uint8_t magicNumber = 0xAA; // 魔数检验，用于检测 eeprom 读出来的数据是否没有出错
    bool factoryResetPending = true;  // 是否需要恢复出厂设置

public:
    // 单例实例的访问器
    static smartConfig_ &getInstance()
    {
        static smartConfig_ instance;
        return instance;
    }
    smartConfig_ &operator=(const smartConfig_ &) = delete; // 屏蔽赋值构造
    smartConfig_(const smartConfig_ &) = delete;            // 屏蔽拷贝构造

public:
    String getSSID();                 // 获取 SSID
    String getPassword();             // 获取密码
    bool checkNetConfigNeeded();      // 判断是否需要进入恢复出厂设置
    void delayRestart(float t);       // 延时重启函数
    void setConfig();                 // 向服务器发送设备上线信息
    void restoreFactory();            // 恢复出厂设置
    void initWiFi();                  // 初始化 WIFI
    void startWiFiConfig();           // 开始 smartconfig
    void loadConfig();                // 加载配置
    void saveConfigToPreferences();   // 保存配置到 preferences
    void loadConfigFromPreferences(); // 从 preferences 加载配置
};

extern smartConfig_ &smartConfig;